#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define PORT 4433

int setup_ssl_CTX(SSL_CTX** ctx) {
    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();
    *ctx = SSL_CTX_new(TLS_server_method());
    if (*ctx == NULL) {
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    // 加载证书和私钥（请替换证书路径）
    if (SSL_CTX_use_certificate_file(*ctx, "server.crt", SSL_FILETYPE_PEM) <= 0 ||
        SSL_CTX_use_PrivateKey_file(*ctx, "server.key", SSL_FILETYPE_PEM) <= 0 ||
        !SSL_CTX_check_private_key(*ctx)) {
        ERR_print_errors_fp(stderr);
        exit(1);
    }
    return 0;
}

void handle_client(int client, SSL_CTX* ctx) {
    SSL* ssl;
    char buf[1024];
    int bytes;

    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, client);
    if (SSL_accept(ssl) == -1) {
        ERR_print_errors_fp(stderr);
    } else {
        bytes = SSL_read(ssl, buf, sizeof(buf));
        buf[bytes] = 0;
        printf("Client msg: \"%s\"\n", buf);
        SSL_write(ssl, "I got your message", strlen("I got your message"));
    }
    SSL_free(ssl);
    close(client);
}

int main() {
    int server, client;
    struct sockaddr_in address;
    socklen_t addrlen = sizeof(address);
    SSL_CTX* ctx;

    setup_ssl_CTX(&ctx);

    server = socket(AF_INET, SOCK_STREAM, 0);
    if (server < 0) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    if (bind(server, (struct sockaddr*)&address, sizeof(address)) < 0) {
        perror("Bind failed");
        exit(EXIT_FAILURE);
    }

    if (listen(server, 3) < 0) {
        perror("Listen failed");
        exit(EXIT_FAILURE);
    }

    while (1) {
        client = accept(server, (struct sockaddr*)&address, &addrlen);
        if (client < 0) {
            perror("Accept failed");
            exit(EXIT_FAILURE);
        }
        handle_client(client, ctx);
    }

    close(server);
    SSL_CTX_free(ctx);
    return 0;
}